﻿using CheckIn.PlanHost.DBModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using JMS;
using Way.EntityDB;
using Microsoft.Extensions.DependencyInjection;
using EJ;
using Org.BouncyCastle.Crypto;
using CheckIn.PlanHost.Dtos;
using Way.Lib;
using JMS.ServerCore.Http;
using CheckIn.PlanHost.DBModels.DB;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Microsoft.Extensions.Logging;

namespace CheckIn.PlanHost.Controllers
{
    [Authorize]
    public class CheckInController : BaseController<PlanDBContext>
    {
        #region 活动
        /// <summary>
        /// 
        /// </summary>
        /// <param name="activities"></param>
        /// <param name="alljoined">当前用户是否已经参加</param>
        /// <returns></returns>
        async Task<Activity[]> fillExt(Activity[] activities, bool alljoined = false)
        {
            var db = this.CurrentDBContext;

            var my_joined_activityIds = activities.Select(m => m.id.Value).ToArray();

            if (alljoined == false)
            {
                my_joined_activityIds = await (from m in db.ActivityJoin
                                               where m.UserId == this.UserId && my_joined_activityIds.Contains(m.ActivityId)
                                               select m.ActivityId).ToArrayAsync();
            }

            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountAdminService = await rc.GetMicroServiceAsync("AccountAdminService");

            foreach (var item in activities)
            {
                if (item.UIExt == null)
                    item.UIExt = new ActivityUIExt();
                item.UIExt.Joined = my_joined_activityIds.Contains(item.id.Value);

                var joinedUserIds = await (from m in db.ActivityJoin
                                           where m.ActivityId == item.id
                                           select m.UserId).ToArrayAsync();

                item.UIExt.JoinedUsers = await accountAdminService.InvokeAsync<UserInfoExt[]>("GetUserInfos", joinedUserIds);
            }

            return activities;
        }

        /// <summary>
        /// 获取推荐的活动信息
        /// </summary>
        /// <returns></returns>
        [Category("活动")]
        public async Task<Activity[]> GetHotActivities()
        {
            var db = this.CurrentDBContext;

            return await fillExt(await (from m in db.Activity
                                        where m.Sort != null
                                        orderby m.Sort, m.id
                                        select m).ToArrayAsync());
        }

        /// <summary>
        /// 获取全部活动信息
        /// </summary>
        /// <param name="pageIndex">页码索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns></returns>
        [Category("活动")]
        public async Task<PageData<Activity>> GetActivities(int pageIndex, int pageSize)
        {
            var db = this.CurrentDBContext;

            var query = from m in db.Activity
                        orderby m.id descending
                        select m;

            var pageData = new PageData<Activity>();
            pageData.Total = await query.CountAsync();
            pageData.Datas = await fillExt(await query.Skip(pageIndex * pageSize).Take(pageSize).ToArrayAsync());
            return pageData;
        }

        /// <summary>
        /// 获取活动详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Category("活动")]
        public async Task<Activity> GetActivitiy(long id)
        {
            var db = this.CurrentDBContext;

            var query = from m in db.Activity
                        where m.id == id
                        select m;

            var data = await query.FirstOrDefaultAsync();

            data.Joined = await (from m in db.ActivityJoin
                                 where m.ActivityId == id && m.UserId == this.UserId
                                 select m).AnyAsync();

            var joinedUserIds = await (from m in db.ActivityJoin
                                       where m.ActivityId == id
                                       select m.UserId).ToArrayAsync();


            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountAdminService = await rc.GetMicroServiceAsync("AccountAdminService");

            data.JoinedUsers = await accountAdminService.InvokeAsync<UserInfoExt[]>("GetUserInfos", joinedUserIds);
            return data;
        }

        /// <summary>
        /// 获取我参加的活动列表
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [Category("活动")]
        public async Task<PageData<Activity>> GetMyActivities(int pageIndex, int pageSize)
        {
            var db = this.CurrentDBContext;

            var query = from m in db.Activity
                        from j in db.ActivityJoin
                        where m.id == j.ActivityId && j.UserId == this.UserId
                        orderby m.id descending
                        select m;

            var datas = await query.Skip(pageIndex * pageSize).Take(pageSize).ToArrayAsync();

            var pageData = new PageData<Activity>();
            pageData.Total = await query.CountAsync();
            pageData.Datas = await fillExt(datas, true);
            return pageData;
        }

        /// <summary>
        /// 当前用户加入活动
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [Category("活动")]
        public async Task JoinActivity(ActivityJoinDto model)
        {
            if (model.ActivityId == 0)
            {
                throw new ServiceException("ActivityId必传");
            }
            var db = this.CurrentDBContext;
            db.BeginTransaction();

            try
            {
                var join = model.ToJsonString().FromJson<ActivityJoin>();
                join.UserId = this.UserId;
                join.JoinTime = DateTime.Now;
                await db.InsertAsync(join);

                var data = new Activity();
                data.SetValue(m => m.JoinCount == m.JoinCount + 1);
                await this.CurrentDBContext.UpdateAsync(data, m => m.id == join.ActivityId);
            }
            catch (RepeatException)
            {

            }
        }
        #endregion

        #region 打卡
        async Task fillCheckInHistories(CheckInHistory[] datas)
        {
            var userids = datas.Select(m => m.UserId).ToArray();
            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountAdminService = await rc.GetMicroServiceAsync("AccountAdminService");

            var userInfos = await accountAdminService.InvokeAsync<UserInfoExt[]>("GetUserInfos", userids);

            var history_ids = datas.Select(m => m.id.Value).ToArray();
            var likeIds = await (from m in this.CurrentDBContext.LikeHistory
                                 where m.UserId == this.UserId && history_ids.Contains(m.CheckInHistoryId)
                                 select m.CheckInHistoryId).ToArrayAsync();


            foreach (var data in datas)
            {
                if (data.Ext == null)
                    data.Ext = new HistoryExt();

                data.Ext.UserInfo = userInfos.FirstOrDefault(m => m.UserId == data.UserId);
                data.Like = likeIds.Contains(data.id.Value);
                data.Title = await (from m in this.CurrentDBContext.CheckInItem
                                    where m.id == data.ItemId
                                    select m.Title).FirstOrDefaultAsync();
            }
        }
        async Task fillCheckInItemsExt(CheckInItem[] items, bool allJoined = false, DateTime? date = null)
        {
            var db = this.CurrentDBContext;

            //获取当前用户参与的项目ids
            long[] ids = null;
            if (!allJoined)
            {
                ids = await (from m in db.UserItem
                             where m.UserId == this.UserId
                             select m.ItemId).ToArrayAsync();
            }

            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountAdminService = await rc.GetMicroServiceAsync("AccountAdminService");



            foreach (var item in items)
            {

                if (item.UIExt == null)
                    item.UIExt = new CheckInItemUIExt();
                item.UIExt.Joined = await db.UserItem.AnyAsync(m => m.UserId == this.UserId && m.ItemId == item.id);

                if (allJoined || ids?.Contains(item.id.Value) == true)
                {
                    if (date == null)
                        date = Global.Timer.Now.Date;

                    var enddate = date.Value.AddDays(1);


                    item.UIExt.Plan = await db.CheckInDayTime.FirstOrDefaultAsync(m => m.UserId == this.UserId && m.ItemId == item.id);
                    item.UIExt.TodayHistories = await (from m in db.CheckInHistory
                                                       where m.ItemId == item.id && m.UserId == this.UserId && m.Date >= date && m.Date < enddate
                                                       select m).ToArrayAsync();
                }

                //获取已经加入的用户
                var userids = await (from m in db.UserItem
                                     where m.ItemId == item.id
                                     select m.UserId).ToListAsync();

                if (item.UIExt.Joined == true && userids.Contains(this.UserId) == false)
                {
                    userids.Insert(0, this.UserId);
                }

                if (userids.Count > 0)
                {
                    item.UIExt.TopJoiners = await accountAdminService.InvokeAsync<UserInfoExt[]>("GetUserInfos", userids);
                }
            }

        }



        /// <summary>
        /// 新建打卡项
        /// </summary>
        /// <param name="model">打卡项信息</param>
        /// <param name="plan">打卡计划，没有计划传null</param>
        /// <returns>返回新建的打卡项信息</returns>
        [Category("打卡")]
        public async Task<CheckInItem> CreateCheckIn(CheckInItem model, CheckInDayTime plan)
        {
            this.CurrentDBContext.BeginTransaction();

            model.OwnerId = this.UserId;
            model.CreateTime = Global.Timer.Now;
            model.JoinCount = 1;
            await this.CurrentDBContext.InsertAsync(model);

            var userItem = new UserItem()
            {
                UserId = this.UserId,
                ItemId = model.id.Value,
                JoinTime = Global.Timer.Now,
            };
            await this.CurrentDBContext.InsertAsync(userItem);

            if (plan != null)
            {
                plan.ItemId = model.id.Value;
                plan.UserId = this.UserId;
                await this.CurrentDBContext.InsertAsync(plan);
            }
            return model;
        }

        /// <summary>
        /// 删除打卡项
        /// 错误码：
        /// 1=打卡项不存在
        /// </summary>
        /// <param name="itemId">打卡项id</param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<HttpResult> DeleteCheckIn(long itemId)
        {
            this.CurrentDBContext.BeginTransaction();

            if (await this.CurrentDBContext.DeleteAsync<CheckInItem>(m => m.id == itemId && m.OwnerId == this.UserId) == 0)
            {
                return Error(new { code = 1, msg = "打卡项不存在" }.ToJsonString());
            }

            return Ok(null);
        }

        /// <summary>
        /// 修改打卡项
        /// 错误码：
        /// 1=打卡项不存在
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<HttpResult> ModifyCheckIn(CheckInItem model)
        {
            this.CurrentDBContext.BeginTransaction();

            if (model.OwnerId != this.UserId)
            {
                return Error(new { msg = "打卡项非你创建" }.ToJsonString());
            }

            var data = await this.CurrentDBContext.CheckInItem.FirstOrDefaultAsync(m => m.id == model.id && m.OwnerId == this.UserId);
            if (data == null)
            {
                return Error(new { code = 1, msg = "打卡项不存在" }.ToJsonString());
            }

            model.CopyValueTo(data, true, false);
            await this.CurrentDBContext.UpdateAsync(data);

            return Ok(null);
        }

        /// <summary>
        /// 获取所有打卡项
        /// </summary>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<CheckInItem[]> GetAllCheckInItems()
        {
            var db = this.CurrentDBContext;

            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountService = await rc.GetMicroServiceAsync("AccountAdminService");

            var ids = await accountService.InvokeAsync<long[]>("GetFllowIds", this.UserId);

            var ret = await (from m in db.CheckInItem
                             where m.OwnerId == 0 || m.OwnerId == this.UserId || (ids.Contains(m.OwnerId) && m.OpenMode != CheckInItem_OpenModeEnum.Personal) || m.OpenMode == CheckInItem_OpenModeEnum.Open
                             orderby m.id descending
                             select m).ToArrayAsync();

            await fillCheckInItemsExt(ret);
            return ret;

        }

        /// <summary>
        /// 获取打卡项信息
        /// </summary>
        /// <param name="itemId">打卡项id</param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<CheckInItem> GetCheckInItem(long itemId)
        {
            var db = this.CurrentDBContext;

            var ret = await (from m in db.CheckInItem
                             where m.id == itemId
                             select m).FirstOrDefaultAsync();

            await fillCheckInItemsExt(new CheckInItem[] { ret });
            return ret;

        }

        /// <summary>
        /// 获取某个人参加的所有项目
        /// </summary>
        /// <param name="userid">关注人id</param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<CheckInItem[]> GetUserCheckInItems(long userid)
        {
            var db = this.CurrentDBContext;

            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountService = await rc.GetMicroServiceAsync("AccountAdminService");

            var isFllowed = await accountService.InvokeAsync<bool>("GetIsFllowed", this.UserId, userid);

            var basequery = db.CheckInItem;
            if (isFllowed)
            {
                basequery = basequery.Where(m => m.OpenMode == CheckInItem_OpenModeEnum.Open || m.OpenMode == CheckInItem_OpenModeEnum.ForFllow || m.OwnerId == this.UserId);
            }
            else
            {
                basequery = basequery.Where(m => m.OpenMode == CheckInItem_OpenModeEnum.Open || m.OwnerId == this.UserId);
            }

            var ret = await (from m in basequery
                             from j in db.UserItem
                             where m.id == j.ItemId && j.UserId == userid
                             orderby m.id descending
                             select m).ToArrayAsync();

            await fillCheckInItemsExt(ret);
            return ret;

        }

        /// <summary>
        /// 获取当前用户的打卡项
        /// </summary>
        /// <param name="date">指定哪一天的打卡项, null表示今天</param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<CheckInItem[]> GetMyCheckInItems(DateTime? date)
        {
            if (date == null)
                date = Global.Timer.Now.Date;
            else
                date = date.Value.Date;


            var db = this.CurrentDBContext;

            var matchDate = date.Value.AddDays(1);
            var ret = await (from m in db.CheckInItem
                             from j in db.UserItem
                             where m.id == j.ItemId && j.UserId == this.UserId && m.CreateTime < matchDate
                             orderby m.id descending
                             select m).ToArrayAsync();

            await fillCheckInItemsExt(ret, true, date);
            return ret;

        }

        /// <summary>
        /// 加入打卡项
        /// </summary>
        /// <param name="itemId"></param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task JoinCheckIn(long itemId)
        {
            this.CurrentDBContext.BeginTransaction();


            var userItem = new UserItem()
            {
                UserId = this.UserId,
                ItemId = itemId,
                JoinTime = Global.Timer.Now,
            };
            try
            {
                await this.CurrentDBContext.InsertAsync(userItem);

                var checkInItem = new CheckInItem();
                checkInItem.SetValue(m => m.JoinCount == m.JoinCount + 1);
                await this.CurrentDBContext.UpdateAsync(checkInItem, m => m.id == itemId);
            }
            catch (RepeatException)
            {

            }

        }

        /// <summary>
        /// 退出打卡项
        /// </summary>
        /// <param name="itemId"></param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task ExitCheckIn(long itemId)
        {
            this.CurrentDBContext.BeginTransaction();

            var checkInItem = new CheckInItem();
            checkInItem.SetValue(m => m.JoinCount == m.JoinCount - 1);
            await this.CurrentDBContext.UpdateAsync(checkInItem, m => m.id == itemId);

            await this.CurrentDBContext.DeleteAsync<UserItem>(m => m.ItemId == itemId && m.UserId == this.UserId);

        }


        /// <summary>
        /// 打卡
        /// </summary>
        /// <param name="model">打卡信息</param>
        /// <returns></returns>
        [Category("打卡")]
        public async Task<CheckInHistory> CheckIn(CheckInModel model)
        {
            if (model.ItemId == 0)
                throw new ServiceException("ItemId必须传");

            var db = this.CurrentDBContext;

            if (await db.UserItem.AnyAsync(m => m.ItemId == model.ItemId && m.UserId == this.UserId) == false)
            {
                throw new ServiceException("需要先加入打卡项");
            }

            db.BeginTransaction();

            var data = model.ToJsonString().FromJson<CheckInHistory>();
            data.UserId = this.UserId;
            data.CreateTime = Global.Timer.Now;

            data.Minutes = 0;
            if (model.OpenUserIds != null && model.OpenUserIds.Length == 0)
                data.OpenUserIds = null;

            try
            {
                if (data.StartTime != null && data.EndTime != null && data.EndTime > data.StartTime)
                    data.Minutes = (int)(data.EndTime.Value - data.StartTime.Value).TotalMinutes;
            }
            catch
            {

            }

            if (data.Date > Global.Timer.Now.Date)
            {
                throw new ServiceException("不能打未来的卡");
            }

            await db.InsertAsync(data);
            return data;
        }
        #endregion

        /// <summary>
        /// 获取组项目的所有子项目信息
        /// </summary>
        /// <param name="groupId">组项目id</param>
        /// <returns></returns>
        [Category("组项目")]
        public async Task<CheckInItem[]> GetGroupItems(long groupId)
        {
            var db = this.CurrentDBContext;

            var ret = await (from m in db.CheckInGroup
                             from c in db.CheckInItem
                             where c.id == m.ChildItemId && m.OwnerItemId == groupId
                             select c).ToArrayAsync();

            await fillCheckInItemsExt(ret);
            return ret;

        }

        /// <summary>
        /// 设置一个组项目所包含的所有子项目
        /// </summary>
        /// <param name="groupId">组项目id</param>
        /// <param name="childItemIds">子项目id</param>
        /// <returns></returns>
        [Category("组项目")]
        public async Task SetGroupItems(long groupId, long[] childItemIds)
        {
            var db = this.CurrentDBContext;
            db.BeginTransaction();

            await db.DeleteAsync<CheckInGroup>(m => m.OwnerItemId == groupId);

            foreach (var itemid in childItemIds)
            {
                if (itemid == groupId)
                    continue;

                await db.InsertAsync(new CheckInGroup
                {
                    OwnerItemId = groupId,
                    ChildItemId = itemid
                });
            }
        }

        #region 打卡详情
        /// <summary>
        /// 获取我的打卡统计详情
        /// </summary>
        /// <returns></returns>
        [Category("打卡详情")]
        public async Task<CheckInStatistics> GetMyCheckInStatistics()
        {
            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountService = await rc.GetMicroServiceAsync("AccountAdminService");



            var data = new CheckInStatistics();

            var task = accountService.InvokeAsync<int>("GetFllowCount", this.UserId).ContinueWith(t =>
            {
                data.FllowCount = t.Result;
            });

            data.TotalMinutes = (await (from m in this.CurrentDBContext.CheckInHistory
                                        where m.UserId == this.UserId
                                        select m.Minutes).SumAsync()).GetValueOrDefault();
            data.JoinCount = await (from m in this.CurrentDBContext.ActivityJoin
                                    where m.UserId == this.UserId
                                    select m).CountAsync();

            data.CheckInDayCount = await (from m in this.CurrentDBContext.CheckInHistory
                                          where m.UserId == this.UserId
                                          group m by m.Date into g
                                          select g.Key).CountAsync();

            await task;

            return data;
        }

        /// <summary>
        /// 获取我的某个打卡项 - 统计详情
        /// </summary>
        /// <param name="itemId"></param>
        /// <returns></returns>
        [Category("打卡详情")]
        public async Task<BaseCheckInStatistics> GetMyCheckInStatisticsDetail(long itemId)
        {

            var data = new BaseCheckInStatistics();

            data.TotalMinutes = (await (from m in this.CurrentDBContext.CheckInHistory
                                        where m.UserId == this.UserId && m.ItemId == itemId
                                        select m.Minutes).SumAsync()).GetValueOrDefault();

            data.CheckInDayCount = await (from m in this.CurrentDBContext.CheckInHistory
                                          where m.UserId == this.UserId && m.ItemId == itemId
                                          group m by m.Date into g
                                          select g.Key).CountAsync();

            return data;
        }
        /// <summary>
        /// 获取打卡项的打卡记录
        /// </summary>
        /// <param name="checkInItemId">打卡项id</param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [Category("打卡详情")]
        public async Task<PageData<CheckInHistory>> GetCheckInHistories(long checkInItemId, int pageIndex, int pageSize)
        {
            var pageData = new PageData<CheckInHistory>();
            var basequery = this.CurrentDBContext.CheckInHistory;


            basequery = basequery.Where(m => m.OpenUserIds == null || m.UserId == this.UserId || Microsoft.EntityFrameworkCore.NpgsqlJsonDbFunctionsExtensions.JsonContains(EF.Functions, m.OpenUserIds, new long[] { this.UserId }));


            var query = from m in basequery
                        where m.ItemId == checkInItemId
                        orderby m.id descending
                        select m;
            pageData.Total = await query.CountAsync();
            pageData.Datas = await query.Skip(pageIndex * pageSize).Take(pageSize).ToArrayAsync();
            await fillCheckInHistories(pageData.Datas);


            return pageData;
        }

        /// <summary>
        /// 获取打卡项的所有参与人信息
        /// </summary>
        /// <param name="checkInItemId">打卡项id</param>
        /// <returns></returns>
        [Category("打卡详情")]
        public async Task<UserInfoExt[]> GetCheckInUsers(long checkInItemId)
        {
            var userids = await (from m in this.CurrentDBContext.UserItem
                                 where m.ItemId == checkInItemId
                                 select m.UserId).ToArrayAsync();

            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountAdminService = await rc.GetMicroServiceAsync("AccountAdminService");

            return await accountAdminService.InvokeAsync<UserInfoExt[]>("GetUserInfos", userids);
        }
        #endregion

        #region 打卡计划
        /// <summary>
        /// 创建打卡计划
        /// </summary>
        /// <returns></returns>
        [Category("打卡计划")]
        public async Task CreatePlan(CheckInDayTime model)
        {
            this.CurrentDBContext.BeginTransaction();

            try
            {
                await this.CurrentDBContext.InsertAsync(model);

            }
            catch (RepeatException)
            {

            }

        }


        /// <summary>
        /// 修改打卡计划
        /// </summary>
        /// <returns></returns>
        [Category("打卡计划")]
        public async Task ModifyPlan(CheckInDayTime model)
        {
            if (model.UserId != this.UserId)
                throw new ServiceException("不是本人的计划");

            this.CurrentDBContext.BeginTransaction();

            var data = await this.CurrentDBContext.CheckInDayTime.FirstOrDefaultAsync(m => m.UserId == this.UserId && m.ItemId == model.ItemId);
            model.CopyValueTo(data, true, false);
            await this.CurrentDBContext.UpdateAsync(data);

        }

        /// <summary>
        /// 删除计划
        /// </summary>
        /// <param name="planId">计划id</param>
        /// <returns></returns>
        /// <exception cref="ServiceException"></exception>
        [Category("打卡计划")]
        public async Task DeletePlan(long planId)
        {
            this.CurrentDBContext.BeginTransaction();

            await this.CurrentDBContext.DeleteAsync<CheckInDayTime>(m => m.id == planId && m.UserId == this.UserId);

        }

        /// <summary>
        /// 获取我的打卡计划
        /// </summary>
        /// <param name="itemId">打卡项id</param>
        /// <returns></returns>
        [Category("打卡计划")]
        public async Task<CheckInDayTime[]> GetMyPlans(long itemId)
        {
            return await (from m in this.CurrentDBContext.CheckInDayTime
                          where m.ItemId == itemId && m.UserId == this.UserId
                          select m).ToArrayAsync();

        }
        #endregion

        #region 打卡记录
        /// <summary>
        /// 获取打卡记录详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Category("打卡记录")]
        public async Task<CheckInHistory> GetHistory(long id)
        {
            var db = this.CurrentDBContext;

            var query = from m in db.CheckInHistory
                        where m.id == id
                        select m;

            var datas = await query.ToArrayAsync();
            await fillCheckInHistories(datas);
            return datas[0];
        }
        /// <summary>
        /// 获取所有关注人/或者指定人的打卡记录
        /// </summary>
        /// <param name="pageIndex">页码索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="userid">指定关注人，null表示所有</param>
        /// <returns></returns>
        [Category("打卡记录")]
        public async Task<PageData<CheckInHistory>> GetFllowHistories(int pageIndex, int pageSize, long? userid)
        {
            var db = this.CurrentDBContext;
            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountService = await rc.GetMicroServiceAsync("AccountAdminService");

            var ids = await accountService.InvokeAsync<long[]>("GetFllowIds", this.UserId);

            if (userid != null)
                ids = new long[] { userid.Value };

            var basequery = db.CheckInHistory;

            basequery = basequery.Where(m => m.OpenUserIds == null || m.UserId == this.UserId || Microsoft.EntityFrameworkCore.NpgsqlJsonDbFunctionsExtensions.JsonContains(EF.Functions, m.OpenUserIds, new long[] { this.UserId }));

            var query = (from m in basequery
                         where ids.Contains(m.UserId)
                         orderby m.id descending
                         select m);

            var pageData = new PageData<CheckInHistory>();
            pageData.Total = await query.CountAsync();
            pageData.Datas = await query.Skip(pageIndex * pageSize).Take(pageSize).ToArrayAsync();
            return pageData;
        }


        /// <summary>
        /// 获取我的打卡记录
        /// </summary>
        /// <param name="pageIndex">页码索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns></returns>
        [Category("打卡记录")]
        public async Task<PageData<CheckInHistory>> GetMyHistories(int pageIndex, int pageSize)
        {
            var db = this.CurrentDBContext;

            var query = (from m in db.CheckInHistory
                         where m.UserId == this.UserId
                         orderby m.id descending
                         select m);

            var pageData = new PageData<CheckInHistory>();
            pageData.Total = await query.CountAsync();
            pageData.Datas = await query.Skip(pageIndex * pageSize).Take(pageSize).ToArrayAsync();

            await fillCheckInHistories(pageData.Datas);

            return pageData;
        }

        /// <summary>
        /// 获取打卡记录的所有点赞用户
        /// </summary>
        /// <param name="checkInHistoryId">打卡记录id</param>
        /// <returns></returns>
        [Category("打卡记录")]
        public async Task<LikeUsers[]> GetHistoryUsers(long checkInHistoryId)
        {
            var db = this.CurrentDBContext;

            var likeHistories = await (from m in db.LikeHistory
                                       where m.CheckInHistoryId == checkInHistoryId
                                       select m).ToArrayAsync();
            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountService = await rc.GetMicroServiceAsync("AccountAdminService");

            var datas = await accountService.InvokeAsync<LikeUsers[]>("GetUserInfos", likeHistories.Select(m => m.UserId).ToArray());
            foreach (var user in datas)
            {
                user.Time = likeHistories.Where(m => m.UserId == user.UserId).Select(m => m.Time).FirstOrDefault();
            }
            return datas;

        }

        /// <summary>
        /// 删除打卡记录
        /// </summary>
        /// <param name="id">记录id</param>
        /// <returns></returns>
        [Category("打卡记录")]
        public Task DeleteHistory(long id)
        {
            var db = this.CurrentDBContext;

            return db.DeleteAsync<CheckInHistory>(x => x.id == id && x.UserId == this.UserId);
        }
        #endregion

        #region 点赞评论
        async Task fillCommentsExt(HisotryComment[] comments)
        {
            var db = this.CurrentDBContext;

            long[] userids = comments.Select(m => m.CommentUserId).ToArray();

            using var rc = Global.ServiceProvider.GetService<RemoteClient>();
            var accountAdminService = await rc.GetMicroServiceAsync("AccountAdminService");

            var userinfos = await accountAdminService.InvokeAsync<UserInfoExt[]>("GetUserInfos", userids);
            foreach (var item in comments)
            {
                item.CommentUserExt = userinfos.FirstOrDefault(m => m.UserId == item.CommentUserId);
            }
        }



        /// <summary>
        /// 对打卡记录点赞
        /// </summary>
        /// <param name="historiesId">打卡记录id</param>
        /// <returns></returns>
        [Category("点赞评论")]
        public async Task LikePlan(long historiesId)
        {
            this.CurrentDBContext.BeginTransaction();

            try
            {
                await this.CurrentDBContext.InsertAsync(new LikeHistory
                {
                    CheckInHistoryId = historiesId,
                    UserId = this.UserId
                });

                var history = new CheckInHistory();
                history.SetValue(m => m.Likes == m.Likes + 1);
                await this.CurrentDBContext.UpdateAsync(history, m => m.id == historiesId);
            }
            catch (RepeatException ex)
            {

            }

        }

        /// <summary>
        /// 评论打卡记录
        /// </summary>
        /// <param name="historiesId">打卡记录id</param>
        /// <param name="content">评论内容</param>
        /// <returns></returns>
        [Category("点赞评论")]
        public async Task Comment(long historiesId, string content)
        {
            this.CurrentDBContext.BeginTransaction();

            var history = await this.CurrentDBContext.CheckInHistory.FirstOrDefaultAsync(m => m.id == historiesId);
            history.SetValue(m => m.Comments == m.Comments + 1);
            await this.CurrentDBContext.UpdateAsync(history);

            var comment = new HisotryComment();
            comment.UserId = history.UserId;
            comment.CommentUserId = this.UserId;
            comment.Content = content;
            comment.HistoryId = historiesId;
            comment.CreateTime = Global.Timer.Now;
            await this.CurrentDBContext.InsertAsync(comment);

        }

        /// <summary>
        /// 获取打卡记录的所有评论
        /// </summary>
        /// <param name="historiesId">打卡记录id</param>
        /// <param name="pageIndex">页码索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns></returns>
        [Category("点赞评论")]
        public async Task<PageData<HisotryComment>> GetComments(long historiesId, int pageIndex, int pageSize)
        {
            this.CurrentDBContext.BeginTransaction();

            var query = from m in this.CurrentDBContext.HisotryComment
                        where m.HistoryId == historiesId
                        select m;

            var pageData = new PageData<HisotryComment>();
            pageData.Total = await query.CountAsync();
            pageData.Datas = await query.ToArrayAsync();
            await fillCommentsExt(pageData.Datas);
            return pageData;
        }
        #endregion
    }
}
